package sip_core

import (
	"fmt"
	"net"
	"sync"
	"time"

	"github.com/sirupsen/logrus"
)

const userTB = "users"     // 用户表 NVR表
const deviceTB = "devices" // 设备表 摄像头

// new
var (
	// sip服务用户信息
	_serverDevices NVRDevices
	srv            *Server
	_activeDevices ActiveDevices
)

// new ActiveDevices 记录当前活跃设备，请求播放时设备必须处于活跃状态
type ActiveDevices struct {
	sync.Map
}

// new
func (a *ActiveDevices) Get(key string) (NVRDevices, bool) {
	if v, ok := a.Load(key); ok {
		return v.(NVRDevices), ok
	}
	return NVRDevices{}, false
}

// new
// 系统运行信息
var _sysinfo sysInfo

// new
type sysInfo struct {
	// Region 当前域
	Region string `json:"region" bson:"region"  yaml:"region" mapstructure:"region"`
	// UID 用户id固定头部
	UID string `json:"uid" bson:"uid"  yaml:"uid" mapstructure:"uid"`
	// UNUM 当前用户数
	UNUM int `json:"unum" bson:"unum" yaml:"unum" mapstructure:"unum"`
	// DID 设备id固定头部
	DID string `json:"did" bson:"did" yaml:"did" mapstructure:"did"`
	// DNUM 当前设备数
	DNUM int `json:"dnum" bson:"dnum" yaml:"dnum" mapstructure:"dnum"`
	// LID 当前服务id
	LID         string `json:"lid" bson:"lid" yaml:"lid" mapstructure:"lid"`
	MediaServer bool
	// 媒体服务器接流地址
	mediaServerRtpIP net.IP
	// 媒体服务器接流端口
	mediaServerRtpPort int
}

// NVRDevices NVR  设备信息
type NVRDevices struct {
	//DBModel
	// Name 设备名称
	Name string `json:"name" bson:"name"`
	// DeviceID 设备id
	DeviceID string `json:"DeviceID" bson:"DeviceID"`
	// Region 设备域
	Region string `json:"region" bson:"region"`
	// Host Via 地址
	Host string `json:"host" bson:"host"`
	// Port via 端口
	Port string `json:"port" bson:"port"`
	// TransPort via transport
	TransPort string `json:"transport" bson:"transport"`
	// Proto 协议
	Proto string `json:"proto" bson:"proto"`
	// Rport via rport
	Rport string `json:"report" bson:"report"`
	// RAddr via recevied
	RAddr string `json:"raddr" bson:"raddr"`
	// Manufacturer 制造厂商
	Manufacturer string `xml:"Manufacturer" bson:"manufacturer" json:"manufacturer"`
	// 设备类型DVR，NVR
	DeviceType string `xml:"IpcType" bson:"devicetype" json:"devicetype"`
	// Firmware 固件版本
	Firmware string `bson:"firmware" json:"firmware"`
	// Model 型号
	Model  string `bson:"model" json:"model"`
	URIStr string `json:"uri" bson:"uri"`
	// ActiveAt 最后心跳检测时间
	ActiveAt int64 `json:"active" bson:"active"`
	// Regist 是否注册
	Regist bool `json:"regist" bson:"regist"`
	// PWD 密码
	PWD string `json:"pwd" bson:"pwd"`

	//
	ToTag         string
	ToParamsItems map[string]string
	ToDisplayName string

	//注册过期时间
	Expires int64

	//注册时间
	RegistTime int64

	// Sys sysInfo `json:"sysinfo" bson:"-"`
	//设备类型 1=NVR,2=IPC,3=无人机
	IPCType int64
	//父级设备ID
	ParentSipID string
	//是否直连
	IsDirectConnect bool
	//是否在线
	IsOnline bool
	//设备状态 //ERROR,OK
	Status string
	//连接方式 udp/tcp
	ConnType string
	//GB_20000=大师专供
	ConnectSolutionID string

	//----
	addr   *Address
	source net.Addr
}

func (n *NVRDevices) Addr() *Address {
	return n.addr
}

func (n *NVRDevices) Source() net.Addr {
	return n.source
}

// Devices 摄像头信息
type Devices struct {
	//DBModel
	// DeviceID 设备编号
	DeviceID string `xml:"DeviceID" bson:"DeviceID" json:"DeviceID"`
	// Name 设备名称
	Name         string `xml:"Name" bson:"name" json:"name"`
	Manufacturer string `xml:"Manufacturer" bson:"manufacturer" json:"manufacturer"`
	Model        string `xml:"Model" bson:"model" json:"model"`
	Owner        string `xml:"Owner" bson:"owner" json:"owner"`
	CivilCode    string `xml:"CivilCode" bson:"civilcode" json:"civilcode"`
	// Address ip地址
	Address     string `xml:"Address" bson:"address" json:"address"`
	Parental    int    `xml:"Parental" bson:"parental" json:"parental"`
	SafetyWay   int    `xml:"SafetyWay" bson:"safetyway" json:"safetyway"`
	RegisterWay int    `xml:"RegisterWay" bson:"registerway" json:"registerway"`
	Secrecy     int    `xml:"Secrecy" bson:"secrecy" json:"secrecy"`
	// Status 状态  on 在线
	Status string `xml:"Status" bson:"status" json:"status"`
	// PDID 所属用户id
	PDID string `bson:"pdid" json:"pdid"`
	// Active 最后活跃时间
	Active int64  `bson:"active" json:"active"`
	URIStr string `bson:"uri" json:"uri"`

	addr *Address `bson:"-"`
}

func (d *Devices) Addr() *Address {
	return d.addr
}

// 从请求中解析出设备信息
func ParserDevicesFromReqeust(req *Request) (NVRDevices, bool) {
	u := NVRDevices{}
	header, ok := req.From()
	if !ok {
		logrus.Warningln("not found from header from request", req.String())
		return u, false
	}
	if header.Address == nil {
		logrus.Warningln("not found from user from request", req.String())
		return u, false
	}
	if header.Address.User() == nil {
		logrus.Warningln("not found from user from request", req.String())
		return u, false
	}
	u.DeviceID = header.Address.User().String()
	u.Region = header.Address.Host()
	via, ok := req.ViaHop()
	if !ok {
		logrus.Info("not found ViaHop from request", req.String())
		return u, false
	}
	u.Host = via.Host
	u.Port = via.Port.String()
	report, ok := via.Params.Get("rport")
	if ok && report != nil {
		u.Rport = report.String()
	}
	raddr, ok := via.Params.Get("received")
	if ok && raddr != nil {
		u.RAddr = raddr.String()
	}

	u.TransPort = via.Transport
	u.URIStr = header.Address.String()
	u.addr = NewAddressFromFromHeader(header)
	u.source = req.Source()
	u.ToParamsItems = make(map[string]string, 0)

	if u.addr != nil {
		if u.addr.Params != nil {
			for k, v := range u.addr.Params.Items() {
				u.ToParamsItems[k] = v.String()
			}
		}

		if u.addr.DisplayName != nil {
			u.ToDisplayName = u.addr.DisplayName.String()
		}
	}
	return u, true
}

// 获取设备信息（注册设备）
func SipDeviceInfo(to NVRDevices) {
	hb := NewHeaderBuilder().SetTo(to.addr).SetFrom(_serverDevices.addr).AddVia(&ViaHop{
		Params: NewParams().Add("branch", String{Str: GenerateBranch()}),
	}).SetContentType(&ContentTypeXML).SetMethod(MESSAGE)
	req := NewRequest("", MESSAGE, to.addr.URI, DefaultSipVersion, hb.Build(), GetDeviceInfoXML(to.DeviceID))
	req.SetDestination(to.source)

	tx, err := srv.Request(req)
	if err != nil {
		logrus.Warnln("SipDeviceInfo  error,", err)
		return
	}

	_, err = SipResponse(tx)
	if err != nil {
		logrus.Warnln("SipDeviceInfo  response error,", err)
		return
	}
}

// SipCatalog 获取注册设备包含的列表
func SipCatalog(to NVRDevices) {
	hb := NewHeaderBuilder().SetTo(to.addr).SetFrom(_serverDevices.addr).AddVia(&ViaHop{
		Params: NewParams().Add("branch", String{Str: GenerateBranch()}),
	}).SetContentType(&ContentTypeXML).SetMethod(MESSAGE)
	req := NewRequest("", MESSAGE, to.addr.URI, DefaultSipVersion, hb.Build(), GetCatalogXML(to.DeviceID))
	req.SetDestination(to.source)

	tx, err := srv.Request(req)
	if err != nil {
		logrus.Warnln("SipCatalog  error,", err)
		return
	}

	_, err = SipResponse(tx)
	if err != nil {
		logrus.Warnln("SipCatalog  response error,", err)
		return
	}
}

// MessageDeviceInfoResponse 主设备明细返回结构
type MessageDeviceInfoResponse struct {
	CmdType      string `xml:"CmdType"`
	SN           int    `xml:"SN"`
	DeviceID     string `xml:"FuDeviceSipID"`
	DeviceType   string `xml:"IpcType"`
	Manufacturer string `xml:"Manufacturer"`
	Model        string `xml:"Model"`
	Firmware     string `xml:"Firmware"`
}

func SipMessageDeviceInfo(u NVRDevices, body string) error {
	message := &MessageDeviceInfoResponse{}
	if err := XMLDecode([]byte(body), message); err != nil {
		logrus.Errorln("SipMessageDeviceInfo Unmarshal xml err:", err, "body:", body)
		return err
	}
	// update := M{
	// 	"model":        message.Model,
	// 	"devicetype":   message.IpcType,
	// 	"firmware":     message.Firmware,
	// 	"manufacturer": message.Manufacturer,
	// }
	// dbClient.Update(userTB, M{"DeviceID": u.FuDeviceSipID}, M{"$set": update})
	return nil
}

// MessageDeviceListResponse 设备明细列表返回结构
type MessageDeviceListResponse struct {
	CmdType  string    `xml:"CmdType"`
	SN       int       `xml:"SN"`
	DeviceID string    `xml:"FuDeviceSipID"`
	SumNum   int       `xml:"SumNum"`
	Item     []Devices `xml:"DeviceList>Item"`
}

func SipMessageCatalog(u NVRDevices, body string) error {
	message := &MessageDeviceListResponse{}
	if err := XMLDecode([]byte(body), message); err != nil {
		logrus.Errorln("Message Unmarshal xml err:", err, "body:", body)
		return err
	}
	if message.SumNum > 0 {
		device := Devices{}
		for _, d := range message.Item {
			// if err := dbClient.Get(deviceTB, M{"DeviceID": d.FuDeviceSipID, "pdid": message.FuDeviceSipID}, &device); err == nil {
			device.PDID = message.DeviceID
			device.Active = time.Now().Unix()
			device.URIStr = fmt.Sprintf("sip:%s@%s", d.DeviceID, _sysinfo.Region)
			device.Status = TransDeviceStatus(d.Status)
			// dbClient.Update(deviceTB, M{"DeviceID": d.FuDeviceSipID, "pdid": message.FuDeviceSipID}, M{"$set": device})
			// go notify(notifyDeviceActive(device))
			// } else {
			// 	logrus.Infoln("DeviceID not found,DeviceID:", d.FuDeviceSipID, "pdid:", message.FuDeviceSipID, "err", err)
			// }
		}
	}
	return nil
}

var DeviceStatusMap = map[string]string{
	"ON":     "ON",
	"OK":     "ON",
	"ONLINE": "ON",
	"OFFILE": "OFF",
	"OFF":    "OFF",
}

func TransDeviceStatus(status string) string {
	if v, ok := DeviceStatusMap[status]; ok {
		return v
	}
	return status
}
